package com.cci.kangdao.wechatOrder.service.impl;

import com.cci.kangdao.crmapi.CRMResponeEntity;
import com.cci.kangdao.crmapi.CRMServiceApi;
import com.cci.kangdao.dao.WorkOrderFlowTDao;
import com.cci.kangdao.dao.WorkOrderRepairDao;
import com.cci.kangdao.dao.WorkOrderTDao;
import com.cci.kangdao.dao.model.WorkOrderT;
import com.cci.kangdao.redis.RedisClientUtils;
import com.cci.kangdao.service.PropertiesUtils;
import com.cci.kangdao.service.impl.SMSEnum;
import com.cci.kangdao.utilTool.*;
import com.cci.kangdao.wechatOrder.constants.WeChatConstants;
import com.cci.kangdao.wechatOrder.dao.WorkOrderHistoryMsgTDao;
import com.cci.kangdao.wechatOrder.dto.request.ServiceLocationRequest;
import com.cci.kangdao.wechatOrder.dto.response.AnalysisSmsTokenResponse;
import com.cci.kangdao.wechatOrder.enums.LinkSmsTokenStatus;
import com.cci.kangdao.wechatOrder.enums.OrderSourceEnum;
import com.cci.kangdao.wechatOrder.enums.OrderStatus;
import com.cci.kangdao.wechatOrder.exception.NotCheckException;
import com.cci.kangdao.wechatOrder.model.WeChatSmsLinkTokenT;
import com.cci.kangdao.wechatOrder.model.WorkOrderHistoryMsgT;
import com.cci.kangdao.wechatOrder.service.IWeChatNoticeService;
import com.cci.kangdao.wechatOrder.service.IWechatReloadLocationService;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * @description:请求服务发送短信服务
 * @author: zyf
 * @create: 2021-03-23
 */
@Service
public class WechatReloadLocationServiceImpl implements IWechatReloadLocationService {

    private Logger log = Logger.getLogger(this.getClass().getName());

    /**
     * 订单表
     */
    @Resource
    private WorkOrderTDao workOrderTDao;
    /**
     * 工单位置历史表
     */
    @Resource
    private WorkOrderHistoryMsgTDao msgTDao;
    /**
     * 工作单
     */
    @Resource
    private WorkOrderRepairDao workOrderRepairDao;

    /**
     * 缓存工具类
     */
    @Autowired
    private RedisClientUtils redisClientUtils;
    /**
     * 微信通知服务
     */
    @Resource
    private IWeChatNoticeService weChatNoticeService;
    /**
     *
     */
    @Autowired
    private PropertiesUtils propertiesUtils;
    /**
     * 工作流程
     */
    @Resource
    private WorkOrderFlowTDao flowTDao;
    @Resource
    private CRMServiceApi crmServiceApi;
    //需求-----     不创建工单，  获取地理位置
    private String PHONE_LOCATION = "PHONE_LOCATION";
    //保存 token和 phone的对应关系
    private String PHONE_TOKEN = "PHONE_TOKEN";

    public static void main(String[] args) {
        System.out.println(TokenUtils.getTempToken());
    }

    @Transactional
    @Override
    public void getServiceReloadLocationNoWorkOrder(String phone, HttpServletRequest request,

                                                    HttpServletResponse response) throws Exception {
        //清除 上次的位置信息
        redisClientUtils.delkey(PHONE_LOCATION + phone);
        //生成token
        String token = TokenUtils.getTempToken();
        //生成url
        String link = propertiesUtils.getPropertiesValue("updateAddressBeforeWorkOrderCreated");
//        String link = propertiesUtils.getPropertiesValue("smsUploadLink");
        String message = String.format(WeChatConstants.SEND_SMS_CRM_LOCATION_MESSAGE, link + token);

        log.info("发送短信内容如下=" + message);
        //发送短信

        weChatNoticeService.sendSmsNoticeNoWorkOrder(phone, message, token);
        //返回正常数据
        ParameterTool.writeSuccessResponse(response);
    }
    @Transactional
    @Override
    public void reloadLocationSendSms(ServiceLocationRequest locationRequest, HttpServletRequest request,
                                      HttpServletResponse response) throws Exception {
        //查询订单信息
        WorkOrderT order = workOrderTDao.getWorkOrderByOrderId(locationRequest.getOrderId());
        //生成token
        String token = TokenUtils.getTempToken();
        //生成url
        String message = weChatNoticeService.getSmsLinkMessageByOrder(order, token);

        log.info("发送短信内容如下=" + message);
        //发送短信
        weChatNoticeService.sendSmsNotice(order, locationRequest.getCompanyId(), message, token);
        //返回正常数据
        ParameterTool.writeSuccessResponse(response);
    }

    @Transactional
    @Override
    public void analysisToken(ServiceLocationRequest locationRequest, HttpServletRequest request, HttpServletResponse response) throws Exception {

        AnalysisSmsTokenResponse tokenResponse = new AnalysisSmsTokenResponse();
        //
        WeChatSmsLinkTokenT linkTokenT = checkSmsTokenAndFlag(locationRequest.getAccessToken(), WeChatConstants.LINK_FAILURE_MESSAGE);
        // 加锁处理，避免发生多次注册。
        if (!redisClientUtils.lock("WeChatAnalysisLocationLock-" + locationRequest.getAccessToken(), 60L)) {
            ParameterTool.writeErrorResponse(response, -98);
            return;
        }
        try {
            if (linkTokenT.getId() == null){
                linkTokenT =  weChatNoticeService.getSmsLinkTokenByToken(locationRequest.getAccessToken());
            }

            //返回参数
            tokenResponse.setCompanyId(linkTokenT.getCompanyId());
            tokenResponse.setCrmOrderNo(linkTokenT.getCrmOrderNo());
            tokenResponse.setOrderId(linkTokenT.getOrderId());
            //产生页面token
            String timeOutToken = TokenUtils.getToken();
            //获取页面过期时间
            String linkTime = propertiesUtils.getPropertiesValue("redisUploadLocationCacheTime");
            tokenResponse.setToken(timeOutToken);

            //之前关联的所有token置为无效状态
            weChatNoticeService.saveSmsLinkToken(linkTokenT.getId(),linkTokenT.getOrderId(), linkTokenT.getCrmOrderNo(), linkTokenT.getCompanyId(), timeOutToken, linkTime, WeChatConstants.SMS_LINK_TIME_OUT_TYPE);
            //更新短信记录数据标记
//            weChatNoticeService.updateSmsLinkTokenFlagByToken(locationRequest.getAccessToken());
//            redisClientUtils.delkey(linkTokenT.getToken());

            ParameterTool.writeSuccessResponse(response, tokenResponse);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            ParameterTool.writeErrorResponse(response);
        } finally {
            redisClientUtils.delkey("WeChatAnalysisLocationLock-" + locationRequest.getAccessToken());
        }
    }

    @Transactional
    @Override
    public void uploadLocation(ServiceLocationRequest locationRequest, HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (!redisClientUtils.lock("WeChatUploadLocationLock-" + locationRequest.getAccessToken(), 60L)) {
            ParameterTool.writeErrorResponse(response, -98);
            return;
        }
        try {


            Map<String, Object> crmSyncmap = new HashMap<>();
            //
            WeChatSmsLinkTokenT currentToken =  checkTokenAndFlag(locationRequest.getAccessToken(), WeChatConstants.LINK_TIME_OUT_MESSAGE);
            //获取判断位置信息是否完全
            WorkOrderHistoryMsgT historyMsgT = new WorkOrderHistoryMsgT();

            //判断是否有工单信息
            if (null != locationRequest.getOrderId()) {
                Double distance = new Double(0);
                //根据工单ID查询工单信息
                WorkOrderT workOrderT = workOrderTDao.getWorkOrderByOrderId(locationRequest.getOrderId());
                if (workOrderT == null) {
                    throw new NotCheckException("无法查询到工单信息，请确认工单是否为有效工单");
                }
                //判断工单状态是否满足更新
                checkUploadLocationByWorkOrderStatus(workOrderT);

                Map<String, Object> param = new HashMap<>();
                param.put("ServiceStationId", workOrderT.getServiceStationId());

                //查询服务站信息
                Map<String, Object> StationLatLon = workOrderRepairDao.getDistance(param);
                //拼接位置
                String stationLonLat = StationLatLon.get("PositionLon") + "," + StationLatLon.get("PositionLat");
                String FaultLonLat = locationRequest.getLongitude() + "," + locationRequest.getLatitude();
                try {
                    distance = GetDistance.getDistance(stationLonLat, FaultLonLat);
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                    //返回客户
                    ParameterTool.writeResponse(response, SMSEnum.type29.getIndex(), SMSEnum.type29.getName());
                    return;
                }
                //创建
                historyMsgT.setOrderId(locationRequest.getOrderId());
                historyMsgT.setCreator(workOrderT.getCustomerId());
                historyMsgT.setCrmOrderNo(workOrderT.getOrderNoCrm());
                historyMsgT.setLocLat(workOrderT.getLocLat());
                historyMsgT.setLocLon(workOrderT.getLocLon());
                historyMsgT.setLocation(workOrderT.getLocation());
                historyMsgT.setCreateTime(LocalTimeUtil.getRealCurrentTime());
                historyMsgT.setLocCity(workOrderT.getLocCity());
                historyMsgT.setLocProvince(workOrderT.getLocProvince());

                workOrderT.setLocation(locationRequest.getLocation());
                workOrderT.setLocLat(locationRequest.getLatitude());
                workOrderT.setLocLon(locationRequest.getLongitude());
                workOrderT.setGuessDistance(distance.floatValue());
                ;
                workOrderT.setLocProvince(locationRequest.getFaultProvince());
                workOrderT.setLocCity(locationRequest.getFaultCity());
                //更新用户位置状态
                workOrderTDao.updateWorkOrderLocationById(workOrderT);
                crmSyncmap.put("orderNo", workOrderT.getOrderNo());
                crmSyncmap.put("caseNo", workOrderT.getOrderNoCrm());

            } else {
                //保存历史位置记录
                historyMsgT.setCrmOrderNo(locationRequest.getCrmOrderNo());
                historyMsgT.setLocLat(locationRequest.getLatitude());
                historyMsgT.setLocLon(locationRequest.getLongitude());
                historyMsgT.setLocation(locationRequest.getLocation());
                historyMsgT.setCreateTime(LocalTimeUtil.getRealCurrentTime());
                historyMsgT.setLocCity(locationRequest.getFaultCity());
                historyMsgT.setLocProvince(locationRequest.getFaultProvince());
                crmSyncmap.put("caseNo", locationRequest.getCrmOrderNo());
            }


            msgTDao.insert(historyMsgT);
            //更新短信记录数据标记为完成状态
            weChatNoticeService.updateSmsLinkTokenFlagByToken(locationRequest.getAccessToken());
            //保存短信记录数据标记,将其他状态改为失效状态
            weChatNoticeService.updateTokenStatusByBindId(currentToken.getBindId(), LinkSmsTokenStatus.LINK_SMS_TOKEN_FAIL.getCode());

            redisClientUtils.delkey(locationRequest.getAccessToken());

            crmSyncmap.put("faultLat", locationRequest.getLatitude().toString());
            crmSyncmap.put("faultLon", locationRequest.getLongitude().toString());
            crmSyncmap.put("faultLocation", locationRequest.getLocation());
            crmSyncmap.put("systemTime", LocalTimeUtil.getRealCurrentTime());
            crmSyncmap.put("faultProvince", locationRequest.getFaultProvince());
            crmSyncmap.put("faultCity", locationRequest.getFaultCity());
            //同步CRM
            CRMResponeEntity entity = crmServiceApi.syncFaultLocationToCRM(crmSyncmap);
            log.info(entity.getMessage());
            //同步到CRM
            ParameterTool.writeSuccessResponse(response);
        }
        catch (NotCheckException e){
            log.error(e.getMessage(), e);
            ParameterTool.writeResponse(response,e.getCode()==0?-99:e.getCode(),e.getMessage());
        }
        catch (Exception e) {
            log.error(e.getMessage(), e);
            ParameterTool.writeErrorResponse(response);
        } finally {
            redisClientUtils.delkey("WeChatUploadLocationLock-" + locationRequest.getAccessToken());
        }
    }

    @Override
    public void setLocationRedis(@RequestBody ServiceLocationRequest locationRequest, HttpServletRequest request, HttpServletResponse response) throws Exception {
        log.info("接口传参为"+locationRequest);
        try {
            WeChatSmsLinkTokenT currentToken = checkTokenAndFlag(locationRequest.getAccessToken(), WeChatConstants.LINK_TIME_OUT_MESSAGE);
            //获取链接过期时间
            String phone = (String) redisClientUtils.getObject("PHONE_TOKEN" + currentToken.getToken());
            Integer linkTime = Integer.parseInt(propertiesUtils.getPropertiesValue("redisSmsLinkCacheTime"));
            redisClientUtils.setObject(PHONE_LOCATION + phone, locationRequest, 0);
            redisClientUtils.delkey(locationRequest.getAccessToken());
            //更新短信记录数据标记为完成状态
            weChatNoticeService.updateSmsLinkTokenFlagByToken(locationRequest.getAccessToken());
            //保存短信记录数据标记,将其他状态改为失效状态
            weChatNoticeService.updateTokenStatusByBindId(currentToken.getBindId(), LinkSmsTokenStatus.LINK_SMS_TOKEN_FAIL.getCode());
            ParameterTool.writeSuccessResponse(response);
        } catch (NotCheckException e) {
            log.error(e.getMessage(), e);
            ParameterTool.writeResponse(response, e.getCode() == 0 ? -99 : e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            ParameterTool.writeErrorResponse(response);
        } finally {
            redisClientUtils.delkey("WeChatUploadLocationLock-" + locationRequest.getAccessToken());
        }

    }

    @Override
    public void getLocationRedis(String phone, HttpServletRequest request, HttpServletResponse response) {
        try {
            ServiceLocationRequest object = null;
            Object objectredis = redisClientUtils.getObject(PHONE_LOCATION + phone);
            if (null == objectredis) {
                ParameterTool.writeSuccessResponse(response, null);
                return;
            }
            redisClientUtils.delkey(PHONE_LOCATION + phone);
            object = (ServiceLocationRequest) objectredis;
            ParameterTool.writeSuccessResponse(response, object);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private Object responseError(HttpServletResponse response, Integer error) {
        try {
            JSONObject obj = new JSONObject();
            obj.put("status", error);
            obj.put("msg", ApiErrorCode.getInstance().getErrorMsg(error));
            //返回客户
            ParameterTool.writeResponse(response, obj.toString());
            obj = null;
        } catch (JSONException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 校验工单状态
     *
     * @param orderStatus
     * @throws Exception
     */
    private void checkOrderStatus(Integer orderStatus) throws Exception {
        List<Integer> passStatus = Arrays.asList(4, 6, 7, 8, 9);
        if (!passStatus.contains(orderStatus)) {
            throw new NotCheckException("当前工单状态不能更新位置");
        }

    }

    /**
     * 校验token是否有效
     *
     * @param token
     * @throws Exception
     */
    private WeChatSmsLinkTokenT checkTokenAndFlag(String token, String errorMessage) throws Exception {
        WeChatSmsLinkTokenT linkTokenT = null;
        if (token == null) {
            throw new NotCheckException(10,"token不是有效的数据");
        }
        //判断token是否过期
        if (redisClientUtils.exists(token)) {
            linkTokenT = (WeChatSmsLinkTokenT) redisClientUtils.getObject(token);
        } else {
            linkTokenT = weChatNoticeService.getSmsLinkTokenByToken(token);
        }

        if (linkTokenT == null) {
            throw new NotCheckException(30,"一个链接只允许提交一次");
        }

        //查询关联ID是否存在操作过位置上传
        WeChatSmsLinkTokenT otherToken =  weChatNoticeService.selectTokenByTokenAndStatus(linkTokenT.getBindId(),linkTokenT.getToken(),2);
        //判断是否已经有其他用户提交过
        if (!Objects.isNull(otherToken)){
            throw new NotCheckException(20,WeChatConstants.LINK_TOKEN_RELOAD_MESSAGE);
        }
        //判断是否过期
        if (!LocalTimeUtil.isBefore(LocalTimeUtil.getRealCurrentTime(), linkTokenT.getExpireTime())) {
            throw new NotCheckException(errorMessage);
        }
        //判断当前用户是否已经提交过
        if (linkTokenT.getFlag() == LinkSmsTokenStatus.LINK_SMS_TOKEN_FAIL.getCode()) {
            throw new NotCheckException(20,WeChatConstants.LINK_TOKEN_FAILURE_MESSAGE);
        }
        //判断当前用户是否已经提交过
        if (linkTokenT.getFlag() == LinkSmsTokenStatus.LINK_SMS_TOKEN_FINISH.getCode()) {
            throw new NotCheckException(20,WeChatConstants.LINK_TOKEN_RELOAD_MESSAGE);
        }
        return linkTokenT;
    }

    private WeChatSmsLinkTokenT checkSmsTokenAndFlag(String token, String errorMessage) throws Exception {
        WeChatSmsLinkTokenT linkTokenT = null;
        if (token == null) {
            throw new NotCheckException(10,"token不是有效的数据");
        }
        //判断token是否过期
        if (redisClientUtils.exists(token)) {
            linkTokenT = (WeChatSmsLinkTokenT) redisClientUtils.getObject(token);
        } else {
            linkTokenT = weChatNoticeService.getSmsLinkTokenByToken(token);
        }

        if (linkTokenT == null) {
            throw new NotCheckException(30,"一个链接只允许提交一次");
        }

        //判断是否过期
        if (!LocalTimeUtil.isBefore(LocalTimeUtil.getRealCurrentTime(), linkTokenT.getExpireTime())) {
            throw new NotCheckException(errorMessage);
        }

        return linkTokenT;
    }


    /**
     * 检测用户是否
     *
     * @param workOrderT
     * @throws Exception
     */
    private void checkUploadLocationByWorkOrderStatus(WorkOrderT workOrderT) throws Exception {

        if ((OrderSourceEnum.ORDER_SOURCE_400.getCode()==workOrderT.getOrderSource() || OrderSourceEnum.ORDER_SOURCE_CRM_400.getCode()==workOrderT.getOrderSource()) && OrderStatus.ORDER_STATUS_SERVICE.getCode() == workOrderT.getOrderStatus()){
            log.info("当前订单来源为服务商");
            return;
        }

        //是否站外工单
        if (workOrderT.getIsOutside() == 0) {
            throw new NotCheckException("该工单为站内工单，无法更新地址");
        }
        //工单是否已经结束
        checkOrderStatus(workOrderT.getOrderStatus());
        //出发的时间轴操作
        String location = flowTDao.getLocationByOrderIdProcessStatus(workOrderT.getId(), 10);
        if (StringUtils.isNotBlank(location)) {
            throw new NotCheckException("该工单已出发，无法更新地址");
        }
    }


}
